//
//	HOME AUTOMATION GATEWAY PROJECT
//
//  (c) 2008 mocom software GmbH & Co KG
//	for European Microsoft Innovation Center
//
//  $Author: volker $
//  $Date: 2009-02-26 16:55:56 +0100 (Do, 26. Feb 2009) $
//  $Revision: 276 $
//
//  Microsoft dotNetMF Project
//  Copyright ©2001,2002,2003,2004 Microsoft Corporation
//  One Microsoft Way, Redmond, Washington 98052-6399 U.S.A.
//  All rights reserved.
//  MICROSOFT CONFIDENTIAL
//
//-----------------------------------------------------------------------------
#include "rtip.h"
#include "sock.h"
#include "rtipapi.h"
#include "rtpirq.h"
#include "rtp.h"
#include "rtpprint.h"
#include <tinyhal.h>
#include "AX88796B.h"

//***************************************************************************
// Set MII to three-state
//***************************************************************************
#define PHY_ADDR_ALIGN					23	// shift
#define REG_ADDR_ALIGN					18	// shift
#define PRE								((UINT32)(0xFFFFFFFF))
#define MII_READ_FRAME					((UINT32)(0x60000000))
#define MII_WRITE_FRAME 				((UINT32)(0x50020000))
#define MII_MDI_BIT_POSITION			2
#define MII_MDI_MASK					4
#define MII_READ_DATA_MASK				MII_MDI_MASK

#define MiiPhyCtrlReservedBitsMask		((UINT16) 0x007F)
#define MiiPhyStatReservedBitsMask		((UINT16) 0x07C0)
#define MiiPhyNwayReservedBitsMask		((UINT16) 0x1A00)
#define MiiPhyNwayExpReservedBitsMask	((UINT16) 0xFFE0)

// MII read/write
#define MII_MDO_BIT_POSITION			3
#define MII_MDO_MASK					8
#define MII_WRITE						0
#define MII_READ						2
#define MII_CLK 						1

#define MII_WRITE_TS					2

//Data Structure holding PHY's registers mask
static const UINT16 PhyRegsReservedBitsMasks[] = {

  MiiPhyCtrlReservedBitsMask,	// Control reg reserved bits mask
  MiiPhyStatReservedBitsMask,	// Status reg reserved bits
  0,							// PhyID reserved bits mask
  0,							// PhyID reserved bits mask
  MiiPhyNwayReservedBitsMask,	// Nway Local ability reserved bits mask
  MiiPhyNwayReservedBitsMask,	// Nway Partner ability reserved bits mask
  MiiPhyNwayExpReservedBitsMask,// Nway Expansion
  0,0,0,0,0,0,0,0,0,0,0,0,0,	// Other regs
  0,0,0,0,0,0,0,0,0,0,0,0		// Other regs
  };

static const UINT16 uPhyAddr = 0x10;

static void inline A79xClkMDI()
{
	ax_write_reg8(NIC_MII_ACCESS,MII_READ);
	ax_write_reg8(NIC_MII_ACCESS,MII_READ |MII_CLK);
}

static void inline A79xSetIdle()
{
	ax_write_reg8(NIC_MII_ACCESS,MII_WRITE_TS);
	ax_write_reg8(NIC_MII_ACCESS,MII_WRITE_TS |MII_CLK);
}

//***************************************************************************
// Write data to MII
//***************************************************************************
static void A79xWriteMii(UINT32 ulData, UINT16 uDataSize)
{
	for (; uDataSize > 0; uDataSize--)
	{
		UINT32 ulDataBit;

		ulDataBit = (ulData >> (31 - MII_MDO_BIT_POSITION)) & MII_MDO_MASK;
		ax_write_reg8(NIC_MII_ACCESS,MII_WRITE |ulDataBit);
		ax_write_reg8(NIC_MII_ACCESS,MII_WRITE |MII_CLK |ulDataBit);
		ulData <<= 1;
	}
}

//***************************************************************************
// Read the value of the MII register
//***************************************************************************
UINT16 MiiReadRegister(UINT16 uRegNum)
{
	UINT32	ulCommand = ((UINT32)uPhyAddr <<PHY_ADDR_ALIGN)
			|((UINT32)uRegNum <<REG_ADDR_ALIGN)
			|MII_READ_FRAME;
	UINT16	uBitsOfUINT16 = sizeof(UINT16) * 8;
	UINT16	i,retval;
	UINT8	iTemp;

	retval = 0;

	A79xWriteMii(0, 16);
	A79xWriteMii(PRE, (UINT16)(2*uBitsOfUINT16));
	A79xWriteMii(ulCommand, (UINT16)(uBitsOfUINT16-2));
	A79xSetIdle();

	iTemp = ax_read_reg8(NIC_MII_ACCESS);
	if (iTemp & MII_READ_DATA_MASK)
	{
		// TRY AGAIN!
		// some kind of PHY need to do this twice...
		A79xSetIdle();
		iTemp = ax_read_reg8(NIC_MII_ACCESS);
		if (iTemp & MII_READ_DATA_MASK)
			return 0;
	}
	for (i = 0; i < uBitsOfUINT16; i++)
	{
		A79xClkMDI();
		iTemp = ax_read_reg8(NIC_MII_ACCESS);
		retval = (retval << 1) | (UINT16)((iTemp >> MII_MDI_BIT_POSITION) & 0x0001);
	}

	A79xSetIdle();

	return retval & ~PhyRegsReservedBitsMasks[uRegNum];;
}

//***************************************************************************
// Write the value to the MII register
//***************************************************************************
void MiiWriteRegister(UINT16 uRegNum,UINT16 uRegData)
{
	UINT32	ulCommand = ((UINT32)uPhyAddr <<PHY_ADDR_ALIGN)
			|((UINT32)uRegNum <<REG_ADDR_ALIGN)
			|MII_WRITE_FRAME
			|(UINT32)(uRegData & ~PhyRegsReservedBitsMasks[uRegNum]);
	UINT16	uBitsOfUINT16 = sizeof(UINT16) * 8;

	// send idle
	A79xWriteMii(0, 16);
	// send preamble
	A79xWriteMii(PRE, (UINT16)(2*uBitsOfUINT16));
	// send startbit, opcode, PHYADDR, REGADDR, data
	A79xWriteMii(ulCommand, (UINT16)(2*uBitsOfUINT16));
	A79xSetIdle();
}

